#include <stdlib.h>

#include "../hle.h"

#include "../core.h"
#include "__IoFileMgrForUser.h"
#include "__ModuleMgrForUser.h"

/*typedef struct
{
    SceSize size;
    SceUID  mpidtext;
    SceUID  mpiddata;
    u32     flags;
    s8      position;
    s8      access;
    s8      creserved[2];
} SceKernelLMOption;*/

/* TODO: second param */
void sceKernelLoadModule()
{
    char *name = mem_readStr(PARAM(0));
    Module *m = malloc(sizeof(Module));
    SceUID moduleId = __KernelLoadELF(m, name, -1);

    _log(INF, HLE, "%d = sceKernelLoadModule(name = %s, flag = %08x, option = %08x)", moduleId, name, PARAM(1), PARAM(2));
    if (moduleId != -1)
        RETURN(moduleId);
    else
        RETURN(SCE_ERROR_UNKNOWN_MODULE);

    mem_freeStr(name);
}

void sceKernelLoadModuleByID()
{
    FileNode *f = ko_get(PARAM(0));
    Module *m = malloc(sizeof(Module));
    SceUID moduleId = __KernelLoadELFFromHandle(m, f->handle, -1);

    _log(INF, HLE, "%d = sceKernelLoadModuleByID(fid = %d, flags = %d, opt = %08x)", moduleId, PARAM(0), PARAM(1), PARAM(2));
    if (moduleId != -1)
        RETURN(moduleId);
    else
        RETURN(SCE_ERROR_UNKNOWN_MODULE);
}

void sceKernelStartModule()
{
    s32 id = PARAM(0);
    s32 argsize = PARAM(1);
    u32 argptr = PARAM(2);
    u32 ptrReturn = PARAM(3);
    SceKernelSMOption option;
    char *arg = NULL;
    if (mem_isOk(argptr)) {
        arg = malloc(argptr);
        mem_readStruct(argptr, arg, argsize);
    }
    if (mem_isOk(PARAM(4)))
        mem_readStruct(PARAM(4), &option, sizeof(SceKernelSMOption));
    else
        __KernelSetDefaultSMOption(&option);
    _log(INF, HLE, "sceKernelStartModule(%d, asize = %08x, aptr = %08x, retptr = %08x, option = %08x)",
                                         id, argsize,      argptr,      ptrReturn,     PARAM(4));
    if (mem_isOk(ptrReturn))
        mem_write32(ptrReturn, 0);
    __KernelStartModule(id, argsize, arg, &option);
    free(arg);
}

void sceKernelStopModule()
{
    _log(ERR, HLE, "sceKernelStopModule(id = %d, argsize = %d, argptr = %08x, status = %08x, opt = %08x)", PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
}

void sceKernelUnloadModule()
{
    _log(ERR, HLE, "sceKernelUnloadModule(id = %d)", PARAM(0));
}

void sceKernelSelfStopUnloadModule()
{
    _log(ERR, HLE, "0 = sceKernelSelfStopUnloadModule(%d, %d, %08x)", PARAM(0), PARAM(1), PARAM(2));
    RETURN(0);
}

void sceKernelGetModuleIdByAddress()
{
    Module *m;
    u32 i;
    u32 id = PARAM(0);
    for (i = 0; i < MAXCOUNT; i++)
    {
        m = ko_search(i, KO_MODULE);
        if (m && m->entry_addr == id)
        {
            RETURN(i);
            _log(INF, HLE, "%d = sceKernelGetModuleIdByAddress(%08x)", i, id);
            return;
        }
    }
    _log(ERR, HLE, "sceKernelGetModuleIdByAddress(%08x) failed", id);
    RETURN(-1);
}

void sceKernelGetModuleId()
{
    SceUID moduleId = __KernelGetCurModuleId();
    _log(INF, HLE, "%d = sceKernelGetModuleId()", moduleId);
    RETURN(moduleId);
}

void sceKernelStopUnloadSelfModuleWithStatus()
{
    _log(ERR, HLE, "sceKernelStopUnloadSelfModuleWithStatus(exitcode = %d, argsize = %d, argaddr = %08x, statusaddr = %08x, optionsaddr = %08x)",
                                                                 PARAM(0),      PARAM(1),     PARAM(2),       PARAM(3),          PARAM(4));
    core_stop();
    RETURN(0);
}

